
#include "Target.h"

Target::Target(BScene* scene)
{
	_dirtyBox = true;
	_dirtySpace = true;
	_scene = scene;
}
Target::Target(BGroup* group, BScene* scene)
{
	_scene = scene;
	BPickHit* hit = new BPickHit();
	hit->setGroup(group);
	this->addPickHit(hit);
}
Target::Target(BShape* shape, BScene* scene)
{
	_scene = scene;
	BPickHit* hit = new BPickHit();
	hit->setShape(shape);
	this->addPickHit(hit);
}
Target::Target(BShape* shape, BGroup* group, BScene* scene)
{
	_scene = scene;
	BPickHit* hit = new BPickHit();
	hit->setShape(shape);
	hit->setGroup(group);
	this->addPickHit(hit);
}
Target::Target(BShape* shape, BNode* node, BScene* scene)
{
	_scene = scene;
	BPickHit* hit = new BPickHit();
	hit->setShape(shape);
	hit->setNode(node);
	this->addPickHit(hit);
}
Target::Target(BNode* node, BScene* scene)
{
	_scene = scene;
	BPickHit* hit = new BPickHit();
	hit->setNode(node);
	this->addPickHit(hit);
}
Target::Target(BNode* node, BGroup* group, BScene* scene)
{
	_scene = scene;
	BPickHit* hit = new BPickHit();
	hit->setNode(node);
	hit->setGroup(group);
	this->addPickHit(hit);
}
Target::Target(BRestraint* restraint, BScene* scene)
{
	_scene = scene;
	BPickHit* hit = new BPickHit();
	hit->setAsset(restraint);
	this->addPickHit(hit);
}
Target::Target(BRestraint* restraint, BGroup* group, BScene* scene)
{
	_scene = scene;
	BPickHit* hit = new BPickHit();
	hit->setAsset(restraint);
	hit->setGroup(group);
	this->addPickHit(hit);
}
Target::Target(const Target& other)
{
	this->copy(&other);
}
Target::~Target()
{

}

void Target::reset(BScene* scene)
{
	clear();
	_scene = scene;
}
void Target::reset(BShape* shape, BScene* scene)
{
	clear();
	_scene = scene;
	_pickHits.clear();
	BPickHit* hit = new BPickHit();
	hit->setShape(shape);
	this->addPickHit(hit);
}
void Target::reset(BGroup* group, BScene* scene)
{
	clear();
	_scene = scene;
	_pickHits.clear();
	BPickHit* hit = new BPickHit();
	hit->setGroup(group);
	this->addPickHit(hit);
}
void Target::reset(BShape* shape, BGroup* group, BScene* scene)
{
	clear();
	_scene = scene;
	_pickHits.clear();
	BPickHit* hit = new BPickHit();
	hit->setShape(shape);
	hit->setGroup(group);
	this->addPickHit(hit);
}
void Target::reset(BNode* node, BScene* scene)
{
	clear();
	_scene = scene;
	_pickHits.clear();
	BPickHit* hit = new BPickHit();
	hit->setNode(node);
	this->addPickHit(hit);
}
void Target::reset(BShape* shape, BNode* node, BScene* scene)
{
	clear();
	_scene = scene;
	_pickHits.clear();
	BPickHit* hit = new BPickHit();
	hit->setShape(shape);
	hit->setNode(node);
	this->addPickHit(hit);
}
void Target::reset(BNode* node, BGroup* group, BScene* scene)
{
	clear();
	_scene = scene;
	_pickHits.clear();
	BPickHit* hit = new BPickHit();
	hit->setNode(node);
	hit->setGroup(group);
	this->addPickHit(hit);
}

const BBox& Target::box() const
{
	if (_dirtyBox)
	{
		_box.reset();
		if (BPickHit* first = _pickHits.first())
		{
			if (BShape* shape = first->shape())
				_box = shape->box() * shape->matrix();
			else if (BNode* node = first->node())
				_box = node->box() * node->matrix();
			else if (BGroup* group = first->group())
				_box = group->box();
			for (int i = 1; i < _pickHits.size(); i++)
			{
				BPickHit* hit = _pickHits[i];
				if (BShape* shape = hit->shape())
					_box.expand(shape->box() * shape->matrix());
				else if (BNode* node = hit->node())
					_box.expand(node->box() * node->matrix());
				else if (BGroup* group = hit->group())
					_box.expand(group->box());
			}
		}
		_dirtyBox = false;
	}
	return _box;
}
const BSpace& Target::space() const
{
	if (_dirtySpace)
	{
		_space.reset();
		if (BPickHit* firstItem = _pickHits.first())
		{
			if (BShape* shape = firstItem->shape())
			{
				BBox box = shape->space();
				if (BNode* node = firstItem->node())
					box *= node->matrix();
				_space = box.space();
			}
			else if (BNode* node = firstItem->node())
				_space = node->space();
			else if (BGroup* group = firstItem->group())
				_space = group->space();
			for (int i = 1; i < _pickHits.size(); i++)
			{
				BPickHit* hit = _pickHits[i];
				if (BShape* shape = hit->shape())
					_space.expand(shape->space());
				else if (BNode* node = hit->node())
					_space.expand(node->space());
				else if (BGroup* group = hit->group())
					_space.expand(group->space());
			}
		}
		_dirtySpace = false;
	}
	return _space;
}

void Target::copy(const Target* other)
{
	_dirtyBox = other->_dirtyBox;
	_box = other->_box;
	_dirtySpace = other->_dirtySpace;
	_space = other->_space;
	_scene = other->_scene;
	_pickHits = other->_pickHits;
}

BScene* Target::scene()
{
	return _scene;
}
const BScene* Target::scene() const
{
	return _scene;
}

BGroup* Target::root()
{
	if (_pickHits.size() == 1)
	{
		const BPickHit* hit = _pickHits.first();
		if (BGroup* group = hit->group())
		{
			while (BGroup* parent = group->parent())
				group = parent;
			return group;
		}
	}
	return 0;
}
const BGroup* Target::root() const
{
	if (_pickHits.size() == 1)
	{
		const BPickHit* hit = _pickHits.first();
		if (const BGroup* group = hit->group())
		{
			while (const BGroup* parent = group->parent())
				group = parent;
			return group;
		}
	}
	return 0;
}

BString Target::path() const
{
	BString str;
	if (_pickHits.size() == 1)
	{
		const BPickHit* hit = _pickHits.first();
		if (const BGroup* group = hit->group())
		{
			str = group->name();
			while (const BGroup* parent = group->parent())
			{
				str.prepend('/');
				str.prepend(parent->name());
				group = parent;
			}
		}
		if (BNode* node = hit->node())
			str << '/' << node->name();
		if (BShape* shape = hit->shape())
			str << '/' << shape->name();
	}
	return str;
}

void Target::append(BGroup* group)
{
	BPickHit* hit = new BPickHit();
	hit->setGroup(group);
	this->addPickHit(hit);
}
void Target::append(BShape* shape)
{
	BPickHit* hit = new BPickHit();
	hit->setShape(shape);
	this->addPickHit(hit);
}
void Target::append(BShape* shape, BGroup* group)
{
	BPickHit* hit = new BPickHit();
	hit->setShape(shape);
	hit->setGroup(group);
	this->addPickHit(hit);
}
void Target::append(BShape* shape, BNode* node)
{
	BPickHit* hit = new BPickHit();
	hit->setShape(shape);
	hit->setNode(node);
	this->addPickHit(hit);
}
void Target::append(BNode* node)
{
	BPickHit* hit = new BPickHit();
	hit->setNode(node);
	this->addPickHit(hit);
}
void Target::append(BNode* node, BGroup* group)
{
	BPickHit* hit = new BPickHit();
	hit->setNode(node);
	hit->setGroup(group);
	this->addPickHit(hit);
}
void Target::append(BScript* script)
{
	BPickHit* hit = new BPickHit();
	hit->setAsset(script);
	this->addPickHit(hit);
}
void Target::append(BScript* script, BGroup* group)
{
	BPickHit* hit = new BPickHit();
	hit->setAsset(script);
	hit->setGroup(group);
	this->addPickHit(hit);
}
void Target::append(BRestraint* restraint)
{
	BPickHit* hit = new BPickHit();
	hit->setAsset(restraint);
	this->addPickHit(hit);
}
void Target::append(BRestraint* restraint, BGroup* group)
{
	BPickHit* hit = new BPickHit();
	hit->setAsset(restraint);
	hit->setGroup(group);
	this->addPickHit(hit);
}

bool Target::addPickHit(BPickHit* hit)
{
	if (hit && _pickHits.append(hit))
	{
		if (BShape* shape = hit->shape())
		{
			shape->setProperty("selected", true);
		}
		_dirtyBox = true;
		_dirtySpace = true;
		return true;
	}
	return false;
}
bool Target::removePickHit(BPickHit* hit)
{
	if (BShape* shape = hit->shape())
	{
		shape->setProperty("selected", false);
	}
	_dirtyBox = true;
	_dirtySpace = true;
	return _pickHits.remove(hit);
}
BPickHit* Target::matchPickHit(BPickHit* hit)
{
	if (!hit)
		return 0;
	for (int i = 0; i < _pickHits.size(); i++)
	{
		BPickHit* pitem = _pickHits[i];
		if (pitem->group() == hit->group() &&
			pitem->node() == hit->node() &&
			pitem->shape() == hit->shape() &&
			pitem->element() == hit->element())
		{
			return pitem;
		}
	}
	return 0;
}

int Target::pickHitCount() const
{
	return _pickHits.size();
}
BPickHit* Target::pickHit(int index)
{
	return _pickHits(index);
}
BPickHit* Target::pickHit(const BShape* shape)
{
	for (int i = 0; i < _pickHits.size(); i++)
	{
		if (_pickHits[i]->shape() == shape)
		{
			return _pickHits[i];
		}
	}
	return 0;
}

BNode* Target::findNode(BNode* node) const
{
	for (int i = 0; i < _pickHits.size(); i++)
	{
		if (_pickHits[i]->node() == node)
		{
			return node;
		}
	}
	return 0;
}
bool Target::contain(BObject* object) const
{
	for (int i = 0; i < _pickHits.size(); i++)
	{
		if (_pickHits[i]->group() == object)
			return true;
		if (_pickHits[i]->shape() == object)
			return true;
		if (_pickHits[i]->node() == object)
			return true;
	}
	return false;
}

BObject* Target::object(int index) const
{
	if (!_pickHits.check(index))
		return 0;
	BPickHit* hit = _pickHits[index];
	if (BObject* object = hit->asset())
		return object;
	if (BGroup* group = hit->group())
		return group;
	if (BShape* shape = hit->shape())
		return shape;
	if (BNode* node = hit->node())
		return node;
	return 0;
}
BShape* Target::shape(int index) const
{
	if (!_pickHits.check(index))
		return 0;
	BPickHit* hit = _pickHits[index];
	BShape* shape = hit->shape();
	return shape;
}
BNode* Target::node(int index) const
{
	if (!_pickHits.check(index))
		return 0;
	BPickHit* hit = _pickHits[index];
	BNode* node = hit->node();
	return node;
}
BGroup* Target::group(int index) const
{
	if (!_pickHits.check(index))
		return 0;
	BPickHit* hit = _pickHits[index];
	BGroup* group = hit->group();
	return group;
}

BObject* Target::object() const
{
	if (_pickHits.size() != 1)
		return 0;
	BPickHit* hit = _pickHits.first();
	if (BShape* shape = hit->shape())
		return shape;
	if (BNode* node = hit->node())
		return node;
	if (BGroup* group = hit->group())
		return group;
	return hit->asset();
}
BShape* Target::shape() const
{
	if (_pickHits.size() != 1)
		return 0;
	BPickHit* hit = _pickHits.first();
	return hit->shape();
}
BElement* Target::element() const
{
	if (_pickHits.size() != 1)
		return 0;
	BPickHit* hit = _pickHits.first();
	return hit->element();
}
BNode* Target::node() const
{
	if (_pickHits.size() != 1)
		return 0;
	BPickHit* hit = _pickHits.first();
	return hit->node();
}
BGroup* Target::group() const
{
	if (_pickHits.size() != 1)
		return 0;
	BPickHit* hit = _pickHits.first();
	return hit->group();
}

bool Target::empty() const
{
	return _pickHits.empty();
}
void Target::clear()
{
	_dirtySpace = false;
	_space.reset();
	for (int i = 0; i < _pickHits.size(); i++)
	{
		if (BShape* shape = _pickHits[i]->shape())
		{
			shape->setProperty("selected", false);
		}
	}
	_pickHits.clear();
}
void Target::dirty()
{
	_dirtyBox = true;
	_dirtySpace = true;
	this->emit(Signal_Dirty);
}

